const articleDao = require("@/dao/article");
const z_base_Dao = require("@/dao/z_base");
const tagDao = require("@/dao/tag");
const commentDao = require("@/dao/comment");
const ArticleModal = require("@/model/Article");
const CategoryModal = require("@/model/Category");
const TagModal = require("@/model/tag");
const Redis = require("@/utils/redis");
const { KEYS } = require("@/server/z_enter");
const blogInfoService = require("@/server/blog_info");
const { cloneDeep } = require("lodash");
const { ErrorCode } = require("@/utils/r/code");
const sequelize = require("@/model/sequelizeBaseConfig");
const { QueryTypes } = require("sequelize");
const article = {
  async GetList(query) {
    //根据前端传递的可选参数获取对应的文章列表信息
    let { articleList, total } = await articleDao.GetList(query);
    //点赞数量map
    let likeCountMap = await Redis.HGetAll(KEYS.KEY_ARTICLE_LIKE_COUNT);
    let viewCountZ = await Redis.ZRangeWithScores(
      KEYS.KEY_ARTICLE_VIEW_COUNT,
      0,
      -1
    );
    //访问数量
    let viewCountMap = getViewCountMap(viewCountZ);

    //格式化部分数据
    for (let i = 0; i < articleList.length; i++) {
      articleList[i].view_count = viewCountMap.get(articleList[i].id) || 0;
      articleList[i].like_count =
        parseInt(likeCountMap.get(articleList[i].id)) || 0;

      if (articleList[i]?.tag_names) {
        articleList[i].tag_names = articleList[i].tag_names.split(",");
      } else {
        articleList[i].tag_names = []; //没有设置标签的时候设置空
      }

      articleList[i].key = parseInt(
        String(Math.random()).slice(2, 9),
        16
      ).toString();
    }

    return {
      total,
      pageData: articleList,
      pageNum: +query.page_num,
      pageSize: +query.page_size,
    };
  },
  async UpdateTop(data) {
    const updata_data = {
      updated_at: new Date().toLocaleString(),
      is_top: data.is_top,
    };
    await z_base_Dao.Update(ArticleModal.Article, updata_data, { id: data.id });
  },
  async GetInfo(id) {
    const article = await z_base_Dao.GetOne(ArticleModal.Article, { id: id });
    const category = await z_base_Dao.GetOne(CategoryModal.CategoryVo, {
      id: article.category_id,
    });
    const tagNames = await tagDao.GetTagNamesByArtId(id);
    if (category.id != 0) {
      article.category_name = category.name;
    }
    article.tag_names = tagNames;
    return article;
  },
  /**
   *
   * @param {*} data
   * @param {*} id 用户id
   */
  async SaveOrUpdate(data, id) {
    if (!data.img) {
      //如果图片不存在，设置默认图片
      const { article_cover } = await blogInfoService.GetBlogConfig();
      data.img = article_cover;
    }

    const article = cloneDeep(data);

    article.user_id = id;
    // 维护 [文章-分类] 关联
    const category = await saveArticleCategory(data);

    if (category) {
      //给文章信息中绑定id
      article.category_id = category.id;
    }

    // 先 添加/更新 文章, 可以获取到 ID
    //文章更新的时候会携带id
    article.updated_at = new Date().toLocaleString();
    if (!article.id) {
      article.create_at = new Date().toLocaleString();
      //文章编号不存在，则创建 (创建成功会返回数据)
      const result = await z_base_Dao.Create(ArticleModal.Article, article);
      // 往原数据身上绑定文章id信息
      article.id = result.id;
    } else {
      //更新文章
      await z_base_Dao.Update(ArticleModal.Article, article, {
        id: article.id,
      });
    }
    //新建文章后数据库操作完毕
    await saveArticleTag(data, article.id);
    return ErrorCode.OK;
  },
  /**
   * 软删除(回收站)
   * @param {*} ids 数组id
   * @param {*} is_delete
   */
  async SoftDelete(ids, is_delete) {
    //软删除的数据 is_delete均设置为1 且置顶的也全部设置is_top =0
    const is_top = 0;
    await z_base_Dao.Updates(
      ArticleModal.Article,
      { is_top, is_delete },
      { id: ids }
    );
    return ErrorCode.OK;
  },
  async Delete(ids) {
    await z_base_Dao.Delete(ArticleModal.ArticleTag, { article_id: ids });
    await z_base_Dao.Delete(ArticleModal.Article, { id: ids });
    return ErrorCode.OK;
  },
  async Import(title, content, user_id) {
    const { article_cover } = await blogInfoService.GetBlogConfig();

    await z_base_Dao.Create(ArticleModal.Article, {
      title,
      user_id,
      content,
      type: 1, //默认原创
      status: 1, //默认公开
      img: article_cover, //图片默认地址
      updated_at: new Date().toLocaleString(),
      create_at: new Date().toLocaleString(),
    });
  },
  async GetFrontList(query) {
    const { list } = await articleDao.GetFrontList(query);
    return list;
  },
  async GetFrontInfo(id) {
    if (!id) return {};
    // 查询具体文章
    let article = await articleDao.GetInfoById(id);
    article.tags = article.tags?.split(",") || []; //导入的文章默认是没有标签的
    // 查询推荐文章 (6篇)
    article.recommend_articles = await articleDao.GetRecommendList(id, 6);
    // 查询最新文章 (5篇)
    article.newest_articles = await articleDao.GetNewestList(5);
    // 更新文章浏览量 TODO: 删除文章时删除其浏览量
    await Redis.ZincrBy(KEYS.KEY_ARTICLE_VIEW_COUNT, id.toString(), 1);
    // 获取上一篇文章, 下一篇文章
    article.last_article = await articleDao.GetLast(id);
    article.next_article = await articleDao.GetNext(id);
    // 点赞量, 浏览量
    article.view_count = await Redis.ZScore(
      KEYS.KEY_ARTICLE_VIEW_COUNT,
      id.toString()
    );
    article.like_count = await Redis.HGet(
      KEYS.KEY_ARTICLE_LIKE_COUNT,
      id.toString()
    );
    // 评论数量
    article.comment_count = await commentDao.GetArticleCommentCount(id);
    return article;
  },
  async SaveLike(uid, articleId) {
    // 记录某个用户已经对某个文章点过赞
    const articleLikeUserKey = KEYS.KEY_ARTICLE_USER_LIKE_SET + uid;
    // 该文章已经被记录过, 再点赞就是取消点赞
    let flag = await Redis.SIsMember(articleLikeUserKey, articleId);
    if (flag) {
      await Redis.SRem(articleLikeUserKey, articleId);
      await Redis.HIncrBy(KEYS.KEY_ARTICLE_LIKE_COUNT, toString(articleId), -1);
    } else {
      //未被记录
      await Redis.SAdd(articleLikeUserKey, articleId);
      await Redis.HIncrBy(KEYS.KEY_ARTICLE_LIKE_COUNT, toString(articleId, 1));
    }
    return ErrorCode.OK;
  },
  async GetArchiveList(query) {
    let { list, total } = await articleDao.GetFrontList(query);

    let archives = [];
    list.forEach((item) => {
      archives.push({
        id: item.id,
        title: item.title,
        created_at: item.created_at,
      });
    });
    return {
      total,
      pageSize: +query.page_size,
      pageNum: +query.page_num,
      pageData: archives,
    };
  },
  async Search(query) {
    let list = [];
    let articleList = await sequelize.query(
      "SELECT * FROM article WHERE is_delete = 0 AND status = 1 AND (title LIKE ? OR content LIKE ?)",
      {
        replacements: [`%${query.keyword}%`, `%${query.keyword}%`],
        type: QueryTypes.SELECT,
      }
    );

    for (let article of articleList) {
      let title = article.title.replace(
        new RegExp(query.keyword, "g"),
        `<span style='color:#f47466'>${query.keyword}</span>`
      );
      let content = article.content;
      // 找到关键字在文章中的起始位置
      let keywordStartIndex = content.indexOf(query.keyword);
      if (keywordStartIndex != -1) {
        //存在关键字
        let preIndex = 0;
        let afterIndex = 0;
        if (keywordStartIndex > 25) {
          //关键字前25范围
          preIndex = keywordStartIndex - 25;
        }
        let preText = content.substring(preIndex, keywordStartIndex);
        //关键字在文章中的结束位置
        let keywordEndIndex = keywordStartIndex + query.keyword.length;
        let afterLength = content.length - keywordEndIndex;
        if (afterLength > 175) {
          //判断关键字结束位置往后的剩余内容是否长度超过175
          afterIndex = keywordEndIndex + 175;
        } else {
          afterIndex = keywordEndIndex + afterLength;
        }
        let afterText = content.substring(keywordStartIndex, afterIndex);
        // 高亮内容中的关键字
        content =
          preText +
          afterText.replace(
            new RegExp(query.keyword, "g"),
            `<span style='color:#f47466'>${query.keyword}</span>`
          );
      }
      list.push({
        id: article.id,
        title: title,
        content,
      });
    }
    return list;
  },
};

function getViewCountMap(rz) {
  const viewCountMap = new Map();
  rz.forEach((article) => {
    const id = +article.member;
    const count = +article.score;
    viewCountMap.set(id, count);
  });
  return viewCountMap;
}

// 维护 [文章-分类] 关联
async function saveArticleCategory(data) {
  const category = await z_base_Dao.GetOne(CategoryModal.CategoryVo, {
    name: data.category_name,
  });

  return category;
}
// 维护 [文章-标签] 关联
async function saveArticleTag(data, article_id) {
  //data为初始前端传递来的文章表单信息
  if (data.id) {
    // 清除文章对应的标签关联
    await z_base_Dao.Delete(ArticleModal.ArticleTag, { article_id: data.id });
  }
  // 遍历 req.TagNames 中传来的标签, 不存在则新建
  let articleTags = []; // 文章-标签 关系
  for (let tag_name of data.tag_names) {
    const tag = await z_base_Dao.GetOne(TagModal.TagVO, { name: tag_name });
    if (!tag) {
      // 不存在则创建
      const update_data = {
        create_at: new Date().toLocaleString(),
        updated_at: new Date().toLocaleString(),
        name: tag_name,
      };
      tag = await z_base_Dao.Create(TagModal.TagVO, update_data);
    }
    articleTags.push({
      article_id: article_id,
      tag_id: tag.id,
    });
  }
  //集体插入
  await ArticleModal.ArticleTag.bulkCreate(articleTags);
}
module.exports = article;
